using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Samples.SsbTransportChannel;
using System.Transactions;
using System.ServiceModel;
using System.Data.SqlClient;

namespace SsbTransportTestSuite.Services
{

    class TestPersistentServiceInstanceProvider : SsbConversationInstanceProvider<TestPersistentService>
    {

        protected override TestPersistentService GetInstance(SsbConversationContext conversationContext, SqlConnection con)
        {
            string sql = @"select ServiceInstanceXML, ServiceInstanceBLOB 
                           from OrderServiceInstanceCache
                           where CGID = @conversationGroup";
            int ServiceInstanceXML = 0;
            int ServiceInstanceBLOB = 1;
            SqlCommand cmd = new SqlCommand(sql, con);
            cmd.Parameters.Add("@conversationGroup", System.Data.SqlDbType.UniqueIdentifier).Value = conversationContext.ConversationGroupId;
            using (SqlDataReader r = cmd.ExecuteReader())
            {
                if (!r.Read())
                {
                    return new TestPersistentService();
                }

                //use this constructor to disable xml serialization assembly reuse in case the app doesn't have permissions
                System.Xml.Serialization.XmlRootAttribute xRoot = new System.Xml.Serialization.XmlRootAttribute();
                xRoot.ElementName = "TestPersistentService";
                System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(TestPersistentService), xRoot);

                TestPersistentService instanceXml = (TestPersistentService)ser.Deserialize(r.GetSqlXml(ServiceInstanceXML).CreateReader());
                //return instanceXml;
      
                System.Runtime.Serialization.Formatters.Binary.BinaryFormatter fmt = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
                byte[] buf = (byte[])r[ServiceInstanceBLOB];

                TestPersistentService instanceBlob = (TestPersistentService)fmt.Deserialize(new System.IO.MemoryStream(buf));
                return instanceBlob;
                
                
            }
            
            
        }

        protected override void ReleaseInstance(Guid conversationGroupId, TestPersistentService instance, SqlConnection con)
        {
            string sql = @"
                    update OrderServiceInstanceCache 
                    set ServiceInstanceXML = @ServiceInstanceXML, 
                        ServiceInstanceBLOB = @ServiceInstanceBLOB
                    where CGID = @conversationGroup
                    if (@@rowcount = 0)
                    begin
                      insert into OrderServiceInstanceCache(CGID,ServiceInstanceXML,ServiceInstanceBLOB)
                      values(@conversationGroup,@ServiceInstanceXML,@ServiceInstanceBLOB)
                    end
                    ";

            SqlCommand cmd = new SqlCommand(sql, con);
            cmd.Parameters.Add("@conversationGroup", System.Data.SqlDbType.UniqueIdentifier).Value = conversationGroupId;
            
            SqlParameter pServiceInstanceXML = cmd.Parameters.Add("@ServiceInstanceXML", System.Data.SqlDbType.Xml);


            //use this constructor to disable xml serialization assembly reuse in case the app doesn't have permissions
            System.Xml.Serialization.XmlRootAttribute xRoot = new System.Xml.Serialization.XmlRootAttribute();
            xRoot.ElementName = "TestPersistentService";
            System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(TestPersistentService), xRoot);


            System.IO.StringWriter xmlbuf = new System.IO.StringWriter();
            ser.Serialize(xmlbuf, instance);
            //Console.WriteLine(xmlbuf.ToString());
            pServiceInstanceXML.Value = new System.Xml.XmlTextReader(new System.IO.StringReader(xmlbuf.ToString()));

            SqlParameter pServiceInstanceBLOB = cmd.Parameters.Add("@ServiceInstanceBLOB", System.Data.SqlDbType.VarBinary, -1);
            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter fmt = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
            System.IO.MemoryStream bytebuf = new System.IO.MemoryStream();
            fmt.Serialize(bytebuf, instance);
            byte[] buf = bytebuf.GetBuffer();
            pServiceInstanceBLOB.Value = buf;

            cmd.ExecuteNonQuery();
            
        }
    }
    [System.Xml.Serialization.XmlRoot]
    [Serializable]
    public class TestPersistentService : IOrderProcessing
    {
        #region IOrderProcessing Members

        [System.Xml.Serialization.XmlElement]
        Order order;

        [System.Xml.Serialization.XmlElement]
        List<OrderItem> orderItems = new List<OrderItem>();
     
        public void BeginOrder(Order order)
        {
            Console.WriteLine("BeginOrder called");
            if (this.order != null)
            {
                throw new InvalidOperationException("Order Already Begun");
            }
            this.order = order;
            // save order to database
            SsbConversationGroupReceiver receiver = OperationContext.Current.Channel.GetProperty<SsbConversationGroupReceiver>();
            using (TransactionScope scope = new TransactionScope(receiver.GetTransaction()))
            {
                Transaction.Current.TransactionCompleted += delegate(object tsCompletedSender, TransactionEventArgs tsCompletedArgs)
                {
                    Console.WriteLine("Transaction Completed {0}", tsCompletedArgs.Transaction.TransactionInformation.Status);
                };
                DBUtils.AddServiceOrder(receiver.GetConnection(), receiver.ConversationGroupId, order);
                scope.Complete();
            }
        }

        public void AddOrderItem(OrderItem item)
        {
            Console.WriteLine("AddOrderItem called");
            orderItems.Add(item);
            // add order to database
            SsbConversationGroupReceiver receiver = OperationContext.Current.Channel.GetProperty<SsbConversationGroupReceiver>();
            using (TransactionScope scope = new TransactionScope(receiver.GetTransaction()))
            {
                DBUtils.AddServiceOrderItem(receiver.GetConnection(), receiver.ConversationGroupId, item);
                scope.Complete();
            }
        }

        public void EndOrder()
        {
            Console.WriteLine("EndOrder called");
            // update order status and send confirmation
            SsbConversationGroupReceiver receiver = OperationContext.Current.Channel.GetProperty<SsbConversationGroupReceiver>();
            SqlConnection cn=receiver.GetConnection();
            Guid cgid=receiver.ConversationGroupId;
            using (TransactionScope scope = new TransactionScope(receiver.GetTransaction()))
            {
                IOrderNotification client = receiver.GetCallback<IOrderNotification>();
                DBUtils.UpdateServiceOrder(cn, cgid, OrderStatus.Confirmed);
                client.ConfirmOrder();
                DBUtils.UpdateServiceOrder(cn, cgid, OrderStatus.Prepared);
                client.UpdateOrderStatus(OrderStatus.Prepared);
                DBUtils.UpdateServiceOrder(cn, cgid, OrderStatus.Shipped);
                client.UpdateOrderStatus(OrderStatus.Shipped);
                scope.Complete();
            }
        }

        #endregion
    }
}
